#![feature(test)]
extern crate test;

use std::alloc::{GlobalAlloc, Layout, System};
use std::time::{Duration, Instant};
use test::Bencher;
use topic1::Allocator;

static MIMALLOC: Allocator = Allocator::new();
const TIMEOUT: Duration = Duration::from_secs(1);

#[bench]
fn bench_small_alloc_libc(b: &mut Bencher) {
    b.iter(|| {
        let layout = Layout::from_size_align(24, 8).unwrap();
        unsafe {
            let ptr = System.alloc(layout);
            System.dealloc(ptr, layout);
        }
    });
}

#[bench]
fn bench_small_alloc_mimalloc(b: &mut Bencher) {
    b.iter(|| {
        let layout = Layout::from_size_align(24, 8).unwrap();
        unsafe {
            let ptr = MIMALLOC.alloc(layout);
            MIMALLOC.dealloc(ptr, layout);
        }
    });
}

#[bench]
fn bench_medium_alloc_libc(b: &mut Bencher) {
    b.iter(|| {
        let layout = Layout::from_size_align(4096, 8).unwrap();
        unsafe {
            let ptr = System.alloc(layout);
            System.dealloc(ptr, layout);
        }
    });
}

#[bench]
fn bench_medium_alloc_mimalloc(b: &mut Bencher) {
    b.iter(|| {
        let start = Instant::now();
        let layout = Layout::from_size_align(4096, 8).unwrap();
        unsafe {
            let ptr = MIMALLOC.alloc(layout);
            if start.elapsed() > TIMEOUT {
                panic!("Allocation timed out");
            }
            MIMALLOC.dealloc(ptr, layout);
            if start.elapsed() > TIMEOUT {
                panic!("Deallocation timed out");
            }
        }
    });
}

#[bench]
fn bench_bulk_small_alloc_libc(b: &mut Bencher) {
    b.iter(|| {
        let mut ptrs = Vec::with_capacity(1000);
        let layout = Layout::from_size_align(24, 8).unwrap();

        // Allocate 1000 small objects
        for _ in 0..1000 {
            unsafe {
                ptrs.push(System.alloc(layout));
            }
        }

        // Free them in reverse order
        while let Some(ptr) = ptrs.pop() {
            unsafe {
                System.dealloc(ptr, layout);
            }
        }
    });
}

#[bench]
fn bench_bulk_small_alloc_mimalloc(b: &mut Bencher) {
    b.iter(|| {
        let mut ptrs = Vec::with_capacity(1000);
        let layout = Layout::from_size_align(24, 8).unwrap();

        // Allocate 1000 small objects
        for _ in 0..1000 {
            unsafe {
                ptrs.push(MIMALLOC.alloc(layout));
            }
        }

        // Free them in reverse order
        while let Some(ptr) = ptrs.pop() {
            unsafe {
                MIMALLOC.dealloc(ptr, layout);
            }
        }
    });
}

// Multi-threaded benchmark
#[bench]
fn bench_mt_small_alloc_libc(b: &mut Bencher) {
    use std::thread;

    b.iter(|| {
        let mut handles = Vec::new();

        // Spawn 4 threads
        for _ in 0..4 {
            handles.push(thread::spawn(|| {
                let layout = Layout::from_size_align(24, 8).unwrap();
                for _ in 0..250 {
                    unsafe {
                        let ptr = System.alloc(layout);
                        System.dealloc(ptr, layout);
                    }
                }
            }));
        }

        // Wait for all threads
        for handle in handles {
            handle.join().unwrap();
        }
    });
}

#[bench]
fn bench_mt_small_alloc_mimalloc(b: &mut Bencher) {
    use std::thread;

    b.iter(|| {
        let mut handles = Vec::new();

        // Spawn 4 threads
        for _ in 0..4 {
            handles.push(thread::spawn(|| {
                let layout = Layout::from_size_align(24, 8).unwrap();
                for _ in 0..250 {
                    unsafe {
                        let ptr = MIMALLOC.alloc(layout);
                        MIMALLOC.dealloc(ptr, layout);
                    }
                }
            }));
        }

        // Wait for all threads
        for handle in handles {
            handle.join().unwrap();
        }
    });
}
